13.3 内部类
13.3.1 概述
什么是内部类
将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。
13.3.2 成员内部类
成员内部类 :定义在类中、方法外的类。
定义格式:
1 2 3 4
| class 外部类 { class 内部类{ } }
|
在描述事物时,若一个事物内部还包含其他事物,就可以使用内部类这种结构。比如,汽车类Car
中包含发动机类Engine
,这时,Engine
就可以使用内部类来描述,定义在成员位置。
代码举例:
1 2 3 4
| class Car { class Engine { } }
|
访问特点
- 内部类可以直接访问外部类的成员,包括私有成员。
- 外部类要访问内部类的成员,必须要建立内部类的对象。
创建内部类对象格式:
1
| 外部类名.内部类名 对象名 = new 外部类型().new 内部类型();
|
访问演示,代码如下:
定义类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Person { private boolean live = true; class Heart { public void jump() { if (live) { System.out.println("心脏在跳动"); } else { System.out.println("心脏不跳了"); } } } public boolean isLive() { return live; } public void setLive(boolean live) { this.live = live; } }
|
定义测试类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class InnerDemo { public static void main(String[] args) { Person p = new Person(); Heart heart = p.new Heart(); heart.jump(); p.setLive(false); heart.jump(); } }
|
内部类仍然是一个独立的类,在编译之后会内部类会被编译成独立的.class
文件,但是前面冠以外部类的类名和$
符号。
比如,Person$Heart.class
13.3.3 局部内部类
如果希望访问所在方法的局部变量,那么这个局部变量必须是【有效final的】。
备注:从Java 8+开始,只要局部变量事实不变,那么final关键字可以省略。
原因:
- new出来的对象在堆内存当中。
- 局部变量是跟着方法走的,在栈内存当中。
- 方法运行结束之后,立刻出栈,局部变量就会立刻消失。
- 但是new出来的对象会在堆当中持续存在,直到垃圾回收消失。
1 2 3 4 5 6 7 8 9 10
| public class MyOuter { public void methodOuter() { int num = 10; class MyInner { public void methodInner() { System.out.println(num); } } } }
|
13.3.4 匿名内部类
- 匿名内部类:是内部类的简化写法。它的本质是一个带具体实现的 父类或者父接口的 匿名子类对象。
开发中,最常用到的内部类就是匿名内部类了。以接口举例,当你使用一个接口时,似乎得做如下几步操作:
- 定义子类
- 重写接口中的方法
- 创建子类对象
- 调用重写后的方法
我们的目的,最终只是为了调用方法,那么能不能简化一下,把以上四步合成一步呢?匿名内部类就是做这样的快捷方式。
前提
格式
1 2 3 4 5 6 7
| new 父类名或者接口名(){ @Override public void method() { } };
|
使用方式
以接口为例,匿名内部类的使用,代码如下:
定义接口:
1 2 3
| public abstract class FlyAble{ public abstract void fly(); }
|
创建匿名内部类,并调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class InnerDemo { public static void main(String[] args) {
FlyAble f = new FlyAble(){ public void fly() { System.out.println("我飞了~~~"); } }; f.fly(); } }
|
通常在方法的形式参数是接口或者抽象类时,也可以将匿名内部类作为参数传递。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class InnerDemo2 { public static void main(String[] args) {
FlyAble f = new FlyAble(){ public void fly() { System.out.println("我飞了~~~"); } }; showFly(f); } public static void showFly(FlyAble f) { f.fly(); } }
|
以上两步,也可以简化为一步,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class InnerDemo3 { public static void main(String[] args) {
showFly( new FlyAble(){ public void fly() { System.out.println("我飞了~~~"); } }); } public static void showFly(FlyAble f) { f.fly(); } }
|
13.3.5 匿名对象
代码演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| public class DemoMain {
public static void main(String[] args) { MyInterface objA = new MyInterface() { @Override public void method1() { System.out.println("匿名内部类实现了方法!111-A"); } @Override public void method2() { System.out.println("匿名内部类实现了方法!222-A"); } }; System.out.println("----------------"); objA.method1(); System.out.println("----------------"); objA.method2(); System.out.println("=================");
new MyInterface() { @Override public void method1() { System.out.println("匿名内部类实现了方法!111-B"); } @Override public void method2() { System.out.println("匿名内部类实现了方法!222-B"); } }.method1(); System.out.println("----------------"); new MyInterface() { @Override public void method1() { System.out.println("匿名内部类实现了方法!111-B"); } @Override public void method2() { System.out.println("匿名内部类实现了方法!222-B"); } }.method2(); } }
|
注意事项
- 匿名内部类,在【创建对象】的时候,只能使用唯一一次。
如果希望多次创建对象,而且类的内容一样的话,那么就需要使用单独定义的实现类了。
- 匿名对象,在【调用方法】的时候,只能调用唯一一次。
如果希望同一个对象,调用多次方法,那么必须给对象起个名字。
- 匿名内部类是省略了【实现类/子类名称】,但是匿名对象是省略了【对象名称】
强调:匿名内部类和匿名对象不是一回事!!!
本文标题:第二部分 第十三章 3.内部类
文章作者:foreverSFJ
发布时间:2019-08-20 11:12:53
最后更新:2019-08-20 11:12:53
原始链接:Notes/Java/Basic/Part02/13_3 内部类.html
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明出处!